package com.bsj.travel.cached.redis;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.bsj.travel.constant.Constants;
import com.bsj.travel.constant.NumericalConstants;
import com.bsj.travel.constants.RedisConstant;
import com.bsj.travel.def.common.DO.DeviceDO;
import com.bsj.travel.def.common.DO.OtaUpgradeDO;
import com.bsj.travel.def.common.DO.ProductDO;
import com.bsj.travel.def.common.DO.ProductTopicDO;
import com.bsj.travel.util.ProductTopicUtil;
import com.bsj.travel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.digester.annotations.rules.SetRoot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.bsj.JedisClusterBSJ;
import redis.clients.bsj.JedisClusterHelper;
import redis.clients.bsj.RedisEval;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yinhao
 * @description redis缓存统一方法
 * @date 2023/10/18
 */
@Slf4j
@Component
public class RedisCached {
    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;


    public <T> boolean set(String key, T value) {
        return set(key, JSON.toJSONString(value), 0);
    }

    public boolean set(String key, String value, int expireTime) {
        jedisClusterBSJ.set(key, value);
        if (expireTime > 0) {
            jedisClusterBSJ.expire(key, expireTime);
        }
        return true;
    }

    public <T> T get(String key, Class<T> clazz) {
        return JSONObject.parseObject(get(key), clazz);
    }

    public String get(String key) {
        return jedisClusterBSJ.get(key);
    }

    public boolean del(String key) {
        return jedisClusterBSJ.del(key) > 0;
    }

    public boolean hdel(String key, String fileId) {
        return jedisClusterBSJ.hdel(key, fileId) > 0;
    }

    public void hset(String key, String fileId, String value) {
        jedisClusterBSJ.hset(key, fileId, value);
    }

    public String hget(String key, String fileId) {
        return jedisClusterBSJ.hget(key, fileId);
    }

    public Map<String, String> hgetAll(String key) {
        return jedisClusterBSJ.hgetAll(key);
    }

    public Set<String> hkeys(String key) {
        return jedisClusterBSJ.hkeys(key);
    }

    public long hlen(String key) {
        return jedisClusterBSJ.hlen(key);
    }

    public boolean exists(String key) {
        return jedisClusterBSJ.exists(key);
    }

    public Long sadd(String key, String value) {
        return jedisClusterBSJ.sadd(key, value);
    }

    public Long srem(String key, String value) {
        return jedisClusterBSJ.srem(key, value);
    }

    public Long pub(byte[] channel, byte[] message) {
        return jedisClusterBSJ.publish(channel, message);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param value
     * @param seconds 单位(秒)
     */
    public void expire(String key, String value, int seconds) {
        set(key, value, seconds);
        jedisClusterBSJ.expire(key, seconds);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param seconds 单位(秒)
     */
    public void expire(String key, int seconds) {
        jedisClusterBSJ.expire(key, seconds);
    }

    public Set<String> smembers(String key) {
        return jedisClusterBSJ.smembers(key);
    }

    public boolean SISMEMBER(String key, String value) {
        return jedisClusterBSJ.sismember(key, value);
    }

    /**
     * 判断该元素是否在set集合中
     *
     * @param key
     * @param value
     * @return
     */
    public boolean sismember(String key, String value) {
        return jedisClusterBSJ.sismember(key, value);
    }

    /**
     * 判断产品信息是否存在
     *
     * @param productKey
     * @return true 存在  false 不存在
     */
    public boolean checkProductExists(String productKey) {
        String productStr = jedisClusterBSJ.hget(RedisConstant.PRODUCT_INFO_KEY, productKey);
        if (StringUtils.isEmpty(productStr)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 获取产品信息
     *
     * @param productKey
     * @return com.bsj.travel.def.common.DO.ProductDO
     * @author ljx
     * @time 2024/3/20 16:33
     */
    public ProductDO hgetProductInfo(String productKey) {
        String productStr = jedisClusterBSJ.hget(RedisConstant.PRODUCT_INFO_KEY, productKey);
        if (productStr == null) {
            return null;
        }
        return JSON.parseObject(productStr, ProductDO.class);
    }

    /**
     * 获取产品下设备信息
     *
     * @param productKey
     * @param deviceName
     * @return
     */
    public DeviceDO hgetDeviceInfo(String productKey, String deviceName) {
        String devStr = jedisClusterBSJ.hget(RedisConstant.PRODUCT_DEVICE_INFO_KEY + productKey, deviceName);
        if (devStr == null) {
            return null;
        }
        return JSON.parseObject(devStr, DeviceDO.class);
    }

    /**
     * 获取产品下设备信息
     *
     * @param productKey
     * @return
     */
    public List<DeviceDO> hgetAllDeviceInfo(String productKey) {
        Map<String, String> map = jedisClusterBSJ.hgetAll(RedisConstant.PRODUCT_DEVICE_INFO_KEY + productKey);
        if (CollectionUtils.isEmpty(map)) {
            return null;
        }
        return map.entrySet().stream().map(value -> {
            return JSON.parseObject(value.getValue(), DeviceDO.class);
        }).collect(Collectors.toList());
    }

    /**
     * 缓存设备信息
     *
     * @param productKey
     * @param deviceDO
     * @return void
     * @author ljx
     * @time 2024/1/15 17:38
     */
    public void hsetDeviceInfo(String productKey, DeviceDO deviceDO) {
        if (deviceDO != null) {
            jedisClusterBSJ.hset(RedisConstant.PRODUCT_DEVICE_INFO_KEY + productKey, deviceDO.getDeviceName(), JSON.toJSONString(deviceDO));
        }
    }

    /**
     * 删除设备信息
     *
     * @param productKey
     * @param deviceName
     * @return void
     * @author ljx
     * @time 2024/1/15 19:11
     */
    public void hdelDeviceInfo(String productKey, String deviceName) {
        jedisClusterBSJ.hdel(RedisConstant.PRODUCT_DEVICE_INFO_KEY + productKey, deviceName);
    }


    /**
     * 获取基础通讯topic
     * @param purview
     * @return
     */
    public Set<String> getBaseTopicClassSet(Integer purview) {
        Set<String> topicClassSet = new HashSet<>();
        String data = jedisClusterBSJ.get(RedisConstant.PRODUCT_BASE_TOPIC_KEY);
        if (data != null) {
            List<ProductTopicDO> topicFromJson = JSON.parseObject(data, new TypeReference<List<ProductTopicDO>>() {
            });
            topicFromJson.forEach(object -> {
                if (object != null) {
                    // 匹配操作权限
                    if ((object.getPurview() != null) && (object.getPurview().equals(purview) || object.getPurview().equals(NumericalConstants.THREE))) {
                        topicClassSet.add(object.getTopicClass());
                    }
                }
            });
        }
        return topicClassSet;
    }

    /**
     * 获取对应的TopicClass
     * 根据productKey和purview
     *
     * @param productKey
     * @return
     */
    public Set<String> getTopicClassSet(String productKey, Integer purview) {
        Set<String> topicClassSet = new HashSet<>();
        Map<String,String> stringMap = jedisClusterBSJ.hgetAll(RedisConstant.PRODUCT_CUSTOMIZE_TOPIC_KEY + productKey);
        if (!stringMap.isEmpty()) {
            for (Map.Entry<String, String> entry : stringMap.entrySet()) {
                String value = entry.getValue();
                ProductTopicDO object = JSON.parseObject(value, ProductTopicDO.class);
                if (object != null) {
                    // 匹配操作权限
                    if ((object.getPurview() != null) && (object.getPurview().equals(purview) || object.getPurview().equals(NumericalConstants.THREE))) {
                        topicClassSet.add(object.getTopicClass());
                    }
                }
            }
        }
        return topicClassSet;
    }

    /**
     * 获取产品下OTA升级包信息
     *
     * @param productKey
     * @param id
     * @return com.bsj.travel.def.common.DO.OtaUpgradeDO
     * @author ljx
     * @time 2024/2/24 10:14
     */
    public OtaUpgradeDO hgetOtaUpgradeInfo(String productKey, Long id) {
        String otaStr = jedisClusterBSJ.hget(RedisConstant.PRODUCT_OTA_INFO_KEY + productKey, id + "");
        if (otaStr == null) {
            return null;
        }
        return JSON.parseObject(otaStr, OtaUpgradeDO.class);
    }

    /**
     * 缓存OTA升级包信息信息
     *
     * @param productKey
     * @param otaUpgradeDO
     * @return void
     * @author ljx
     * @time 2024/2/24 10:16
     */
    public void hsetOtaUpgradeInfo(String productKey, OtaUpgradeDO otaUpgradeDO) {
        if (otaUpgradeDO != null) {
            jedisClusterBSJ.hset(RedisConstant.PRODUCT_OTA_INFO_KEY + productKey, otaUpgradeDO.getId() + "", JSON.toJSONString(otaUpgradeDO));
        }
    }

    /**
     * 删除OTA升级包信息
     *
     * @param productKey
     * @param id
     * @return void
     * @author ljx
     * @time 2024/2/24 10:17
     */
    public void hdelOtaUpgradeInfo(String productKey, Long id) {
        jedisClusterBSJ.hdel(RedisConstant.PRODUCT_OTA_INFO_KEY + productKey, id + "");
    }


    /**
     * 执行lua脚本
     *
     * @param luaScriptStr  脚本内容
     * @param redisEvalList 脚本key/param参数
     * @return
     * @throws Exception
     */
    public Set<Object> mUniqueEval(String luaScriptStr, List<RedisEval> redisEvalList) throws Exception {
        return JedisClusterHelper.mUniqueEval(jedisClusterBSJ, luaScriptStr, redisEvalList);
    }

    /**
     * 获取所有在线设备号
     *
     * @return java.util.List<java.lang.String>
     * @author ljx
     * @time 2024/3/20 17:08
     */
    public List<String> getAllOnlineDeviceName() {
        List<String> deviceNames = new LinkedList<>();
        Map<String, String> map = hgetAll(RedisConstant.SERVER_NODES);
        if (map.isEmpty()) {
            return deviceNames;
        }
        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            String key = entry.getKey();
            Map<String, String> all = hgetAll(RedisConstant.CONNECT_STATUS + key);
            if (CollectionUtils.isEmpty(all)) {
                continue;
            }
            deviceNames.addAll(all.entrySet().stream().map(info -> {
                String str = info.getKey();
                return str.substring(NumericalConstants.ZERO, str.lastIndexOf(Constants.AND_SYMBOL));
            }).collect(Collectors.toList()));
        }
        return deviceNames;
    }


    /**
     * 获取设备在线状态
     * @param username  代表设备编号&产品KEY    * username: 13534912307&b11i2pch3mz
     * @return
     */
    public int getDeviceStatus(String username) {
        int status = NumericalConstants.THREE;
        // 获取所有节点信息
        Map<String, String> map = hgetAll(RedisConstant.SERVER_NODES);
        if (map.isEmpty()) {
            return status;
        }
        for (Map.Entry<String, String> entry : map.entrySet()) {
            // "172.16.16.14:1883" - nodeName
            String key = entry.getKey();
            String clientId = hget(RedisConstant.CONNECT_STATUS + key, username);
            // 存在则代表在线
            if (StringUtils.isNotEmpty(clientId)) {
                status = NumericalConstants.TWO;
                break;
            }
        }
        return status;
    }
}
